﻿using System;

using SharpGL.SceneGraph.Assets;

namespace SharpGL.SceneGraph.Primitives
{
    /// <summary>
    /// The Grid design time primitive is displays a grid in the scene.
    /// </summary>
    public class Grid : ContextualSceneElement, IRenderable
    {
        #region Private Fields

        /// <summary>
        /// The internal display list.
        /// </summary>
        private DisplayList displayList = null;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnCreateInContext(OpenGL gl)
        {
            //  Init display list object. 
            displayList = new DisplayList();

            //  Create the display list 
            displayList.Create(gl);

            //  Begin the display list.
            displayList.Begin(DisplayList.DisplayListMode.Compile);

            //  Render.
            InternalRender(gl);

            //  End the display list.
            displayList.End();
        }

        protected override void OnDestroyInContext(OpenGL gl)
        {
            if (displayList != null)
            {
                displayList.Destroy();
                displayList = null;
            }
        }

        /// <summary>
        /// Simple render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        protected void InternalRender(OpenGL gl)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Push attributes, set the color.
                gl.PushAttrib(OpenGL.GL_CURRENT_BIT | OpenGL.GL_ENABLE_BIT |
                    OpenGL.GL_LINE_BIT);
                gl.Disable(OpenGL.GL_LIGHTING);
                gl.Disable(OpenGL.GL_TEXTURE_2D);
                gl.LineWidth(1.0f);

                //  Draw the grid lines.
                gl.Begin(OpenGL.GL_LINES);
                for (int i = -10; i <= 10; i++)
                {
                    float fcol = ((i % 10) == 0) ? 0.3f : 0.15f;
                    gl.Color(fcol, fcol, fcol);
                    float x = i / 20.0f;
                    gl.Vertex(x, -0.5f, 0.0f);
                    gl.Vertex(x, 0.5f, 0.0f);
                    gl.Vertex(-0.5f, x, 0.0f);
                    gl.Vertex(0.5f, x, 0.0f);
                }
                gl.End();

                //  Restore attributes.
                gl.PopAttrib();
            }
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Grid"/> class.
        /// </summary>
        public Grid()
        {
            Name = "Design Time Grid";
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="renderMode">The render mode.</param>
        public void Render(OpenGL gl, RenderMode renderMode)
        {
            //  Don't render in hittest mode.
            if (renderMode == RenderMode.HitTest)
                return;

            //  If we do not have the display list render grid.
            //  Otherwise, we can simple call the display list.
            if (displayList == null)
                InternalRender(gl);
            else
            {
                ValidateRenderingContext(gl);

                displayList.Call();
            }
        }

        #endregion Public Methods
    }
}
